#include <string.h>
#include "ringbuffer.h"
#include "drv_can.h"
#include "bootloader.h"

/* CAN ring buffer*/
static struct rt_ringbuffer canRxRb;
/* The sizeof(can_msg_t) is 10 bytes, the pool can receive 20 packets */
static rt_uint8_t canRxPool[240];

static void can_gpio_init()
{
    /* enable CAN clock */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_AF);

    /* configure CAN0 GPIO */
    gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
}

static void can_nvic_init()
{
    /* configure CAN0 NVIC */
    can_interrupt_enable(CAN0, CAN_INT_RFNE1);
    nvic_irq_enable(CAN0_RX1_IRQn, 1, 0);
}

static void can_para_init()
{
//    can_parameter_struct can_parameter;
//    can_filter_parameter_struct can_filter;

//    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
//    can_struct_para_init(CAN_INIT_STRUCT, &can_filter);
//    /* initialize CAN register */
//    can_deinit(CAN0);

//    /* initialize CAN parameters */
//    can_parameter.time_triggered = DISABLE;
//    can_parameter.auto_bus_off_recovery = DISABLE;
//    can_parameter.auto_wake_up = DISABLE;
//    can_parameter.auto_retrans = ENABLE;
//    can_parameter.rec_fifo_overwrite = DISABLE;
//    can_parameter.trans_fifo_order = DISABLE;
//    can_parameter.working_mode = CAN_NORMAL_MODE;
//    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
//    can_parameter.time_segment_1 = CAN_BT_BS1_5TQ;
//    can_parameter.time_segment_2 = CAN_BT_BS2_4TQ;
//    can_parameter.prescaler = 6;

//    /* initialize CAN */
//    can_init(CAN0, &can_parameter);

//    /* initialize filter */
//    can_filter.filter_number = 0;
//    can_filter.filter_mode = CAN_FILTERMODE_LIST;
//    can_filter.filter_bits = CAN_FILTERBITS_16BIT;
//    /* filter the recv id */
//    can_filter.filter_list_high = (CURRENT_MOTOR_RECV_ID << 5);
//    can_filter.filter_list_low = (STEERING_RECV_ID << 5);
//    can_filter.filter_mask_high = 0xffff;
//    can_filter.filter_mask_low = 0xffff;
//    can_filter.filter_fifo_number = CAN_FIFO1;
//    can_filter.filter_enable = ENABLE;
//    can_filter_init(&can_filter);
//    
//    /* initialize filter */
//    can_filter.filter_number = 1;
//    can_filter.filter_mode = CAN_FILTERMODE_LIST;
//    can_filter.filter_bits = CAN_FILTERBITS_16BIT;
//    /* filter the recv id */
//    can_filter.filter_list_high = (CAN_CURRENT_BOOT_SEND_ID << 5);
//    can_filter.filter_list_low = (CAN_CURRENT_BOOT_RECV_ID << 5);
//    can_filter.filter_mask_high = 0xffff;
//    can_filter.filter_mask_low = 0xffff;
//    can_filter.filter_fifo_number = CAN_FIFO1;
//    can_filter.filter_enable = ENABLE;
//    can_filter_init(&can_filter);
}

static void can_rb_init()
{
    rt_ringbuffer_init(&canRxRb, canRxPool, sizeof(canRxPool));
}

void can_hw_init()
{
    can_gpio_init();
    can_para_init();
    can_nvic_init();
    can_rb_init();
}

/**
 * @brief Send a CAN message
 *
 * @param msg : cAN message structure
 * @return ErrStatus : SUCCESS or ERROR
 */
ErrStatus can_send_msg(can_msg_def *msg)
{
    can_trasnmit_message_struct txMsg;
    txMsg.tx_sfid = msg->id;
    txMsg.tx_efid = 0x00;
    txMsg.tx_ft = CAN_FT_DATA;
    txMsg.tx_ff = CAN_FF_STANDARD;
    txMsg.tx_dlen = msg->len;
    memcpy(txMsg.tx_data, msg->data, txMsg.tx_dlen);
    if (can_message_transmit(CAN0, &txMsg) == CAN_NOMAILBOX)
    {
        return ERROR;
    }
    return SUCCESS;
}

/**
 * @brief Recv a CAN message
 *
 * @param msg : cAN message structure
 * @return ErrStatus : SUCCESS or ERROR
 */
ErrStatus can_recv_msg(can_msg_def *msg)
{
    uint8_t len = sizeof(can_msg_def);
    if (rt_ringbuffer_get(&canRxRb, (uint8_t *)msg, len) != len)
    {
        return ERROR;
    }

    return SUCCESS;
}

void can_isr_callback()
{
    can_msg_def msg;
    can_receive_message_struct rxMsg;
    can_message_receive(CAN0, CAN_FIFO1, &rxMsg);
    if (rxMsg.rx_dlen)
    {
        memset(&msg, 0, sizeof(msg));
        msg.id = rxMsg.rx_sfid;
        msg.len = rxMsg.rx_dlen;
        memcpy(msg.data, rxMsg.rx_data, msg.len);
        rt_ringbuffer_put_force(&canRxRb, (uint8_t *)&msg, sizeof(can_msg_def));
    }
}
